#pragma once

#include <windows.h>

#include <boost/thread/once.hpp>


#include "XString.h"
#include "Exception.h"



namespace platform {

/**
 * Helper class, used to wrap all registry-access
 * functions
 */
class RegistryHelper
{
public:
	static inline RegistryHelper & GetInstance(void);


	enum RootKeys {
		RK_CURRENT_USER,
		RK_LOCAL_MACHINE,
		RK_ABPA_BASE
	};

	static inline HKEY Root2HKey(const RootKeys root);


	class RegistryKey {
		HKEY _key;

	public:

		RegistryKey(const RootKeys root, const XString &path);

		inline RegistryKey(const HKEY key) : _key(key) {}

		RegistryKey(RegistryKey &key);

		virtual ~RegistryKey(void);

		inline HKEY getRawKey(void) { return _key; }

		__int32 getInt32Value(const XString &name) const;

		void getStringValue(const XString &name, XString &value) const;

		void setValue(const XString &name, __int32 val);

		void setValue(const XString &name, const XString &val);

	private:
		// disallow operator=
		RegistryKey & operator=(const RegistryKey&);

	};


public:
	virtual ~RegistryHelper(void);

private:
	template<bool FORCE>
	static HKEY GetKey(HKEY base, LPCTSTR path);

	RegistryKey _appBaseKey;

	// singleton object
	RegistryHelper(void);
	static inline void CreateInstance(void) { _instance_ptr = new RegistryHelper(); }
	static RegistryHelper *		_instance_ptr;
	static boost::once_flag		_instance_flag;

};

inline RegistryHelper & RegistryHelper::GetInstance(void) {
	boost::call_once(CreateInstance, _instance_flag);
	return *_instance_ptr;
}

inline HKEY RegistryHelper::Root2HKey(const RootKeys root) {
	switch (root) {
		case RK_CURRENT_USER:
			return HKEY_CURRENT_USER;
		case RK_LOCAL_MACHINE:
			return HKEY_LOCAL_MACHINE;
		case RK_ABPA_BASE:
			return GetInstance()._appBaseKey.getRawKey();
		default:
			// unknown type
			THROW(Exception, "unexpected value to Root2HKey");
	}
};



} // end namespace
